package xyz.bali16.module.article.controller;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
import com.gitee.starblues.spring.MainApplicationContext;
import com.gitee.starblues.spring.SpringBeanFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import xyz.bali16.application.core.enums.ApiEnum;
import xyz.bali16.application.core.model.Result;
import xyz.bali16.application.core.model.UserVo;
import xyz.bali16.application.core.utils.AuthUtils;
import xyz.bali16.application.core.utils.IDUtils;
import xyz.bali16.application.core.utils.ResultUtils;
import xyz.bali16.application.entity.User;

import xyz.bali16.application.service.UserService;
import xyz.bali16.module.article.entity.*;
import xyz.bali16.module.article.model.ArticleAddParam;
import xyz.bali16.module.article.model.ArticlePageParam;
import xyz.bali16.module.article.model.ArticleUpdateParam;
import xyz.bali16.module.article.model.tag.TagAddParam;
import xyz.bali16.module.article.service.*;
import xyz.bali16.module.article.service.ArticleService;


import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.*;

import static com.baomidou.mybatisplus.core.toolkit.Wrappers.lambdaQuery;
import static xyz.bali16.application.core.model.Result.*;
import static xyz.bali16.application.core.model.Result.failure;

import static xyz.bali16.module.article.utils.ResultUtils.errorLog;

/**
 * @article-author bali2 on 9/3/2023.
 * @version 1.0
 */
@RestController
@RequestMapping(BaseController.API + "article")
@Api(tags = "文章接口")
@AllArgsConstructor
public class ArticleController extends BaseController {
    public static final Logger logger = LoggerFactory.getLogger(ArticleController.class);
    @Autowired
    private ArticleCategoryService articleCategoryService;
    @Autowired
    private ArticleTagService articleTagService;
    @Autowired
    private ArticleService articleService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private TagService tagService;

    @Autowired
    private ActiveUserServiceCaller activeUserServiceCaller;
    @Autowired
    ArticleRankServiceCaller articleRankServiceCaller;
    @Autowired
    private MainApplicationContext context;
    @Autowired
    MuteServiceCaller muteServiceCaller;

    @Autowired
    @AutowiredType(AutowiredType.Type.PLUGIN_MAIN)
    PreAuthorizeService preAuthorizeService;
    public void handleArticle(Article article) {
        ArticleCategory articleCategory = articleCategoryService.getByArticleId(article.getId());
        if (articleCategory != null && !StringUtils.isBlank(articleCategory.getCategoryId())) {
            Category category = categoryService.getById(articleCategory.getCategoryId());
            article.setCategory(category);
        }
        List<ArticleTag> articleTags = articleTagService.getByArticleId(article.getId());
        if (articleTags != null) {
            List<Tag> tag_list = new ArrayList<>();
            for (ArticleTag articleTag : articleTags) {
                Wrapper<Tag> wrapper = Wrappers.<Tag>lambdaQuery().eq(Tag::getId, articleTag.getTagId());
                Tag tags = tagService.getOne(wrapper);
                tag_list.add(tags);
            }
            article.setTags(tag_list);
        }
        SpringBeanFactory factory = context.getSpringBeanFactory();
        UserService userService = factory.getBean(UserService.class);
        User user = userService.getById(article.getUserId());
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);
        article.setAuthor(userVo);

        if (article.getLikeCount() == null) {
            article.setLikeCount(0L);
        }
    }

    @GetMapping
    @ApiOperation("分页条件查询文章")
    //@PreAuthorize("@article-auth.permission('plugin:article:query')")
    public Result<IPage<Article>> pageQuery(@Valid ArticlePageParam param) {
        if(!preAuthorizeService.permission("plugin:article:query")){
            return failure(ApiEnum.MISSING_PERMISSION);
        }
        // 根据Category名字转化为CategoryId
        String categoryName = param.getCategory();
        if (!StringUtils.isBlank(categoryName)) {
            Wrapper<Category> wrapper = Wrappers.<Category>lambdaQuery().eq(Category::getName, categoryName);
            Category category = categoryService.getOne(wrapper);
            if (category != null) {
                param.setCategoryId(category.getId());
            }
        }
        // 处理文章分页
        IPage<Article> articleIPage = articleService.getPage(param);
        List<Article> articles = articleIPage.getRecords();
        for (Article article : articles) {
            handleArticle(article);
        }
        return success(ApiEnum.GET_SUCCESS, articleIPage);
    }

    @GetMapping("/{articleId}")
    //@PreAuthorize("@article-auth.permission('plugin:article:query')")
    @ApiOperation("查看文章")
    public Result<Article> get(@PathVariable("articleId") String articleId) {
        if(!preAuthorizeService.permission("plugin:article:query")){
            return failure(ApiEnum.MISSING_PERMISSION);
        }
        try {
            Article article = articleService.getById(articleId);
            handleArticle(article);
            //article.setViews(article.getViews()+1); 已经淘汰，优化成redis优先后写入数据库
            // 更新点击次数到redis缓存中
            articleRankServiceCaller.updateTypeCount("views", article.getId(), article.getViews());
            //articleService.saveOrUpdate(article);
            return success(ApiEnum.GET_SUCCESS, article);
        } catch (Exception e) {
            errorLog(logger, e, "获取文章 '{}' 信息失败 {}", articleId, e.getMessage());
            return failure(ApiEnum.GET_ERROR, "获取文章失败", e);
        }
    }

    @PostMapping
    //@PreAuthorize("@article-auth.permission('plugin:article:add')")
    @ApiOperation("添加文章")
    public Result<String> add(@RequestBody @Valid ArticleAddParam param) {
        if(!preAuthorizeService.permission("plugin:article:add")){
            return failure(ApiEnum.MISSING_PERMISSION);
        }
        try {

            SpringBeanFactory factory = context.getSpringBeanFactory();
            UserService userService = factory.getBean(UserService.class);
            User user = userService.getByUsername(AuthUtils.getCurrentUsername());

            if (muteServiceCaller.isMute(user.getUserId())) {
                failure("发帖失败,你已被禁言");
            }
            // 根据Category名字转化成CategoryId
            String categoryName = param.getCategory();
            Wrapper<Category> category_wrapper = Wrappers.<Category>lambdaQuery().eq(Category::getName, categoryName);
            Category category = categoryService.getOne(category_wrapper);
            param.setCategoryId(category.getId());
            // 根据Tag名字转化为TagId
            String tagNames = param.getTagNames();
            List<String> tags = new ArrayList<>();
            List<String> tagsNames = new ArrayList<>();
            if (tagNames.split("-").length > 0) { // 多个标签时候
                for (String tagName : tagNames.split("-")) {
                    tagsNames.add(tagName);
                }
            } else { // 单个标签时候
                tagsNames.add(param.getTagNames());
            }
            for (String tagName : tagsNames) {
                Wrapper<Tag> tag_wrapper = Wrappers.<Tag>lambdaQuery().eq(Tag::getName, tagName);
                Tag tag = tagService.getOne(tag_wrapper);
                String tagId = tag == null ? IDUtils.uuid() : tag.getId();
                if (tag == null) { // 当tag不存在时候要创建tag
                    TagAddParam tagAddParam = new TagAddParam();
                    tagAddParam.setId(tagId);
                    tagAddParam.setName(tagName);
                    tagAddParam.setUrl(tagName);
                    tagService.addTag(tagAddParam);
                }
                tags.add(tagId);
            }
            param.setTagIds(tags);
            // 处理添加业务
            articleService.add(param);
            activeUserServiceCaller.addPostNum(user.getUserId());
            return response(ApiEnum.ADD_SUCCESS);
        } catch (Exception e) {
            errorLog(logger, e, "新增文章 '{}' 信息失败 {}", param.getTitle(), e.getMessage());
            return failure(ApiEnum.ADD_ERROR, "新增文章失败", e);
        }
    }

    @PutMapping
    //@PreAuthorize("@article-auth.permission('plugin:article:update')")
    @ApiOperation("修改文章")
    public Result<String> update(@RequestBody @Valid ArticleUpdateParam param) {
        if(!preAuthorizeService.permission("plugin:article:update")){
            return failure(ApiEnum.MISSING_PERMISSION);
        }
        try {
            articleService.update(param);
            return response(ApiEnum.UPDATE_SUCCESS);
        } catch (Exception e) {
            errorLog(logger, e, "更新文章 '{}' 信息失败 {}", param.getTitle(), e.getMessage());
            return failure(ApiEnum.UPDATE_ERROR, "更新文章失败", e);
        }
    }

    @PutMapping("/{articleId}/{enable}")
    @ApiOperation("修改文章状态")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "articleId", value = "文章id", paramType = "path", required = true),
            @ApiImplicitParam(name = "status", value = "状态（1启用, 0停用）", paramType = "path", required = true)
    })
    //@PreAuthorize("@article-auth.permission('plugin:article:update')")
    public Result<String> updateStatus(@PathVariable("articleId") String articleId,
                                       @PathVariable("enable") Integer enable) {
        if(!preAuthorizeService.permission("plugin:article:update")){
            return failure(ApiEnum.MISSING_PERMISSION);
        }
        String message = enable == 1 ? "启用" : "禁用";
        try {
            articleService.updateStatus(articleId, enable);
            return response(ApiEnum.UPDATE_SUCCESS, message + "成功");
        } catch (Exception e) {
            ResultUtils.errorLog(logger, e, "修改菜单状态失败. {}", e.getMessage());
            return failure(ApiEnum.UPDATE_ERROR, message + "失败", e);
        }
    }

    @DeleteMapping("/{articleId}")
    //@PreAuthorize("@article-auth.permission('plugin:article:delete')")
    @ApiOperation("删除文章")
    @ApiImplicitParam(name = "articleId", value = "文章id", paramType = "path", required = true)
    public Result<String> deleteArticle(@PathVariable("articleId") String articleId) {
        if(!preAuthorizeService.permission("plugin:article:delete")){
            return failure(ApiEnum.MISSING_PERMISSION);
        }
        try {
            articleService.delete(articleId);
            return response(ApiEnum.DELETE_SUCCESS);
        } catch (Exception e) {
            errorLog(logger, e, "删除文章 '{}' 失败. {}", articleId, e.getMessage());
            return failure(ApiEnum.DELETE_ERROR, e);
        }
    }

}
